﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Scripting.Hosting;
using Microsoft.Scripting;
using IronTrishul.Compiler;
using System.Reflection;

namespace IronTrishul
{
    public class WindowProgram
    {
        // Create runtime
        static ScriptRuntime runtime = ScriptRuntime.Create();
        static ScriptScope globals = null;
        static ScriptEngine wsdlscript = null;
        static Dictionary<string, dynamic> globalVariable = new Dictionary<string, dynamic>();

        public static Dictionary<string, dynamic> GlobalVariable
        {
            get { return WindowProgram.globalVariable; }
            set { WindowProgram.globalVariable = value; }
        }

        public static void SetWriteMethod(MethodInfo writeMethod)
        {
            Parser.ConsoleWriteLine = writeMethod;
        }

        static WindowProgram()
        {
            // Preload System assembly
            runtime.LoadAssembly(typeof(string).Assembly);

            // Create a scope at global level
            globals = runtime.CreateScope();

            // Load WSDLScript Engine
            wsdlscript = runtime.GetEngine(typeof(WSDLLanguageContext));


        }

        /// <summary>
        /// Entry point
        /// </summary>
        /// <param name="args"></param>
        static void Run(string[] args)
        {
            // Set Current language
            ScriptEngine current = wsdlscript;
            string command;

            // Interactive command line
            while (true)
            {
                // Write prompt
                WindowProgram.Write(current == wsdlscript ? "rest>> " : "ws>> ");
                command = ReadCommand();

                // Exit
                string lowercommand = command.ToLower();
                if (lowercommand.Equals("exit"))
                    break;

                // Change language
                else if (lowercommand.Equals("mjs"))
                {
                    current = wsdlscript;
                    continue;
                }
                else if (lowercommand.Equals("ipy"))
                {
                    // current = python;
                    continue;
                }

                // Run
                RunProgram(current, command, globals);
            }
        }

        /// <summary>
        /// Run a command on a DLR engine.
        /// </summary>
        /// <param name="engine">engine to use</param>
        /// <param name="command">command to run</param>
        /// <param name="globals">global scope</param>
        static private void RunProgram(ScriptEngine engine, string command, ScriptScope globals)
        {
            ScriptSource src = engine.CreateScriptSourceFromString(command, SourceCodeKind.Statements);
            src.Execute(globals);
        }

        static public void RunProgram(string command)
        {
            ScriptSource src = wsdlscript.CreateScriptSourceFromString(command, SourceCodeKind.Statements);
            src.Execute(globals);
        }

        /// <summary>
        /// Read a multi-line command.
        /// </summary>
        /// <returns>the command</returns>
        static private string ReadCommand()
        {
            // Loop on each line
            StringBuilder command = new StringBuilder();
            while (true)
            {
                // Read a line
                string line = ReadLine();
                command.Append(line);

                // Special command
                string value = command.ToString();
                if (value.Equals("exit") || value.Equals("rest") || value.Equals("ws"))
                    break;

                // Stop if end by ';' or '}'
                int length = line.Length;
                if (length == 0)
                    break;
                char lastchar = line[length - 1];
                if (lastchar == ';' || lastchar == '}')
                    break;

                // Wait for next line
                command.AppendLine();
                WindowProgram.Write("> ");
            }

            return command.ToString();
        }

        static void Write(string line)
        {
            Console.Write(line);
        }
        static void WriteLine(string line)
        {
            Console.WriteLine(line);
        }

        static string ReadLine()
        {
            return Console.ReadLine();
        }
    }
}
